package cn.springcloud.fix.auth.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.authentication.*;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

/**
 * prePostEnabled = true，会解锁 @PreAuthorize 和@PostAuthorize 两个注解
 * securedEnabled = true，会解锁 @Secured 注解
 */
@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    /**
     * 支持多种编码，通过密码的前缀区分编码方式
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        // return PasswordEncoderFactories.createDelegatingPasswordEncoder();
        return new BCryptPasswordEncoder(10);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // http.csrf().disable().authorizeRequests().anyRequest().authenticated();
        http
                .requestMatchers().anyRequest()
                .and()
                .authorizeRequests()
                // .antMatchers("/", "/home", "/login", "/oauth/authorize", "/oauth/*")
                .antMatchers("/oauth/authorize")
                .permitAll()
                .and()
                .formLogin().loginPage("/login")//开发者自定义的登录界面
                .usernameParameter("username")
                .passwordParameter("password")
                .loginProcessingUrl("/login")
                .permitAll()
                .and()
                .httpBasic().disable()
                // .exceptionHandling().accessDeniedPage("/login?authorization_error=true")
                .csrf()
                // .requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize"))
                .disable();

        // http.authorizeRequests().anyRequest().authenticated().and().formLogin().permitAll();

        // http.antMatcher("/**/oauth/**").authorizeRequests()
        //         .antMatchers("/**/admin/**").hasRole("ADMIN")
        //         .antMatchers("/**/user/**").access("hasAnyRole('ADMIN','USER')")
        //         .antMatchers("/**/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
        //         .antMatchers("/**/oauth/**").permitAll()
        //         .anyRequest().authenticated()
        //         .and()
        //         .exceptionHandling()
        //         .accessDeniedHandler((request, response, e) -> {
        //             this.write(response, R.ERROR(403, "没有权限访问！"));
        //         })
        //         .and()
        //
        //         .successHandler((request, response, auth) -> {
        //             UserDetail principal = (UserDetail) auth.getPrincipal();
        //             principal.setPassword("***");
        //             response.setStatus(200);
        //             this.write(response, R.SUCCESS(principal));
        //         })
        //         .failureHandler((request, response, e) -> {
        //             response.setStatus(401);
        //             R r;
        //             if (e instanceof LockedException) {
        //                 r = R.ERROR("账户被锁定，登录失败！");
        //             } else if (e instanceof BadCredentialsException) {
        //                 r = R.ERROR("账户名或密码输入错误，登录失败！");
        //             } else if (e instanceof DisabledException) {
        //                 r = R.ERROR("账户被禁用，登录失败！");
        //             } else if (e instanceof AccountExpiredException) {
        //                 r = R.ERROR("账户已过期，登录失败！");
        //             } else if (e instanceof CredentialsExpiredException) {
        //                 r = R.ERROR("密码已过期，登录失败！");
        //             } else {
        //                 r = R.ERROR(e.getMessage());
        //             }
        //             this.write(response, r);
        //         })
        //         .and()
        //         .logout()
        //         .logoutUrl("/logout")
        //         .clearAuthentication(true)
        //         .invalidateHttpSession(true)
        //         .addLogoutHandler((request, response, auth) -> {
        //
        //         })
        //         .logoutSuccessHandler((request, response, auth) -> {
        //             // response.sendRedirect("/login_page");
        //             this.write(response, R.SUCCESS("注销成功！"));
        //         })
        //         .permitAll()
        //         .and()
        //         .csrf().disable();
    }

    /**
     * ROLE_DBA是终极大Boss，具有所有的权限，ROLE_ADMIN 具有 ROLE_USER 的权限，ROLE_USER则是一个公共角色
     */
    @Bean
    RoleHierarchy roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        String hierarchy = "ROLE_DBA > ROLE_ADMIN > ROLE_USER";
        roleHierarchy.setHierarchy(hierarchy);
        return roleHierarchy;
    }
}
